;(function ($) {
    /**
     * 增加jQuery公共方法
     * 0 EasyVue
     * 1 require
     * 2 define
     * 3 import
     */
    $.extend({
        EasyVue(options) {
            //1.默认参数
            let defaults = {
                dev: true,
                el: '#app',
                api_cxt: '/EasyVue/static/json',
                static_cxt: '/EasyVue/static',
                views: '/views',
                loginUrl: '/login',
                mainUrl: '/admin',
            };
            //2.覆盖默认参数
            $.opts = $.extend({}, defaults, options);

            //3.初始化公共方法
            /**
             * axios 配置
             */
            const AUTH_TOKEN = (function () {
                return localStorage.getItem('token');
            })();
            //跨域带上cookies
            //axios.defaults.withCredentials=true;
            axios.defaults.baseURL = $.opts.api_cxt;
            axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
            // 添加一个请求拦截器
            axios.interceptors.request.use(function (config) {
                if ($.opts.api_cxt === '/EasyVue/static/json') {
                    config.url += '.json';
                }
                let token = localStorage.getItem('token');
                if (config.url.indexOf($.opts.loginUrl) > -1) {
                    token = '';
                    localStorage.setItem('token', token);
                    $.setUserInfo('');
                }
                //config.headers.Authorization = token;
                return config;
            }, function (error) {
                layer.msg(error.config.url + '<br/>' + error.message);
                return Promise.reject(error);
            });

            // 添加一个响应拦截器
            axios.interceptors.response.use(function (res) {
                let token = res.headers.Authorization;
                let redirect = res.headers.redirect;
                if (!token) {
                    redirect = $.opts.loginUrl;
                }
                localStorage.setItem('token', token);
                if (redirect && $.VM) {
                    //$.VM.$router.push({path: redirect});
                }
                return res;
            }, function (error) {
                layer.msg(error.config.url + '<br/>' + error.message);
                return Promise.reject(error);
            });
            /**
             * requireJs 配置
             * 1.调用require后,会调用load方法,这里重新该方法以实现vue组件的异步加载
             * 2.load可以可以理解为函数注册
             * 3.完成load加载,需执行一次define,再执行一次context.completeLoad
             */
            require.config({
                baseUrl: $.opts.static_cxt,
                context: '_',
                waitSeconds: $.opts.dev ? 0 : 7
            });
            require.s.contexts['_'].load = function (moduleName, url) {
                let context = require.s.contexts['_'];
                if (url.substr(-3, 3) === '.js') {
                    //后缀.js方法直接调用原load方法
                    require.load(context, moduleName, url);
                } else {
                    //后缀.vue方法对vue组件进行分解
                    $.get($.opts.static_cxt + $.opts.views + url + '.vue', function (res) {
                        define([], function () {
                            //提取template节点和script节点
                            let el = document.createElement('div');
                            el.innerHTML = res;
                            let tmpl = '';
                            let script = '';
                            for (let i = el.children.length - 1; i > -1; i--) {
                                let child = el.children[i];
                                if (child.tagName === 'TEMPLATE') {
                                    tmpl = child.innerHTML;
                                    el.removeChild(child);
                                } else if (child.tagName === 'SCRIPT') {
                                    script = child.innerHTML;
                                    el.removeChild(child);
                                }
                            }
                            //克隆元素
                            el = $(el.children).clone(true);
                            let jsUrl = url + '.js';
                            require.exec(script);
                            context.completeLoad(jsUrl);
                            return new Promise((resolve, reject) => {
                                require([jsUrl], function (options) {
                                    options.template = tmpl;
                                    debugger;
                                    function addFn(fnName, fn, isBefore) {
                                        if (isBefore === undefined) {
                                            isBefore = true;
                                        }
                                        let localFn = options[fnName];
                                        let localFnType = typeof localFn;
                                        if (localFnType === 'undefined') {
                                            options[fnName] = fn;
                                        } else if (localFnType === 'function') {
                                            if (isBefore) {
                                                options[fnName] = [fn, localFn];
                                            } else {
                                                options[fnName] = [localFn, fn];
                                            }
                                        }
                                    }

                                    //vue 生命周期
                                    addFn('beforeCreate', function () {
                                        debugger;
                                        if (undefined !== options.query) {
                                            this.$router.push({
                                                query: $.extend(true, this.$route.query, options.query)
                                            });
                                        }
                                        console.log('生命周期：beforeCreate');
                                        console.log(this);
                                    });

                                    addFn('created', function () {
                                        debugger;
                                        console.log('生命周期：created');
                                        console.log(this);
                                    });

                                    addFn('beforeMount', function () {
                                        debugger;
                                        console.log('生命周期：beforeMount');
                                        console.log(this);
                                    });

                                    addFn('mounted', function () {
                                        debugger;
                                        console.log('生命周期：mounted');
                                        console.log(this);
                                        $(this.$el).append(el);
                                    });

                                    //keep-alive 激活时触发
                                    addFn('activated', function () {
                                        debugger;
                                        console.log('生命周期：activated');
                                        console.log(this);
                                        $(this.$el).append(el);
                                    });

                                    resolve(options);
                                });
                            });
                        });
                        context.completeLoad(moduleName);
                    });
                }
            };

            //4.加载路由
            const router = new VueRouter();
            $.routes = {
                addRoutes: function (path, url) {
                    if ('string' !== typeof path) {
                        return;
                    }
                    path = path.split('?')[0];
                    if (undefined === url) {
                        url = path;
                    }
                    let route = $.routes[path];
                    if (undefined === route) {
                        let vs = path.substr(0, $.opts.mainUrl.length);
                        if (vs !== $.opts.mainUrl || path === $.opts.mainUrl) {
                            route = {
                                path: path,
                                component: () => ({component: $.import(url)}),
                                children: []
                            };
                        } else {
                            route = $.routes.addRoutes($.opts.mainUrl);
                            let childrenPath = path.replace($.opts.mainUrl, "");
                            route.children.push({
                                path: childrenPath.replace("/", ""),
                                component: () => ({component: $.import(childrenPath + ".vue")})
                            });
                        }
                        $.routes[path] = route;
                        router.addRoutes([route]);
                    }
                    return route;
                }
            };
            const routerPush = router.push;
            router.push = function push(location, onComplete, onAbort) {
                //添加路由规则
                let path = location;
                if ('string' !== typeof location) {
                    path = location.path;
                }
                $.routes.addRoutes(path);
                //原push方法
                return routerPush.call(this, location, onComplete, onAbort).catch(error => error);
            };

            $.VM = new Vue({router}).$mount($.opts.el);
            let toUrl = window.location.hash;
            if (toUrl.indexOf('#') === 0) {
                toUrl = toUrl.substr(1);
            }
            if (toUrl === '/' || toUrl.indexOf('/?') === 0) {
                toUrl = toUrl.replace('/', $.opts.mainUrl);
            }
            let userInfo = $.getUserInfo();
            if (!userInfo && toUrl.indexOf($.opts.loginUrl) !== 0) {
                if (toUrl.indexOf('?redirect=') === -1) {
                    toUrl = '?redirect=' + toUrl;
                }
                toUrl = $.opts.loginUrl + toUrl;
            }
            $.VM.$router.push(toUrl);
        },
        parseQuery(query) {
            let res = {};
            query = query.trim().replace(/^(\?|#|&)/, '');
            if (!query) {
                return res
            }
            query.split('&').forEach(function (param) {
                let parts = param.replace(/\+/g, ' ').split('=');
                let key = decodeURIComponent(parts.shift());
                let val = parts.length > 0 ? decodeURIComponent(parts.join('=')) : null;

                if (res[key] === undefined) {
                    res[key] = val;
                } else if (Array.isArray(res[key])) {
                    res[key].push(val);
                } else {
                    res[key] = [res[key], val];
                }
            });

            return res
        },
        require(deps, callback, errback, optional) {
            let depsType = typeof (deps);
            if ('function' === depsType) {
                callback = deps;
                deps = [];
            } else if ('string' === depsType) {
                deps = [deps];
            }
            require(deps, callback, errback, optional);
        },
        define(deps, callback) {
            let depsType = typeof (deps);
            if ('function' === depsType) {
                callback = deps;
                deps = [];
            } else if ('string' === depsType) {
                deps = [deps];
            }
            define(deps, callback);
        },
        /**
         * import 返回Promise对象
         */
        import(url, notRouter) {
            if ('/' !== url.substr(0, 1)) {
                url = '/' + url;
            }
            let arr = url.split('?');
            url = arr[0];
            let query = {};
            if (arr.length > 1) {
                query = $.parseQuery(arr[1]);
            }
            return new Promise((resolve, reject) => {
                require([url], function (p) {
                    debugger;
                    console.log(p);
                    if (notRouter) {
                        p.then(options => {
                            if (notRouter) {
                                options.query = query;
                            }
                            console.log(options);
                        });
                    }
                    resolve(p);
                });
            });
        },
        getStore(key) {
            return localStorage.getItem(key);
        },
        setStore(key, val) {
            localStorage.setItem(key, val);
            return this;
        },
        getUserInfo() {
            return this.getStore('USER_INFO');
        },
        setUserInfo(userInfo) {
            return this.setStore('USER_INFO', userInfo);
        }
    });
})(window.jQuery);